package com.ms.orm.dboperator;

import com.ms.common.util.CollectionUtils;
import com.ms.orm.exception.BaseSqlException;
import com.ms.orm.conditions.Wrapper;
import com.ms.orm.meta.IPage;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * @author zdh
 * 数据库操作基础类
 * 1） 实际操作基类 BaseEntityDao 实现 全部实现的增删改查
 * 2） 每个Reposity单独实现
 */
public interface DbOperator<T> {


    /**
     * 1、插入一条记录
     * @param entity 实体对象
     * @return 插入成功记录数
     */
    int save(T entity);

    /**
     * 2、根据 ID 删除
     * @param id 主键ID
     * @return 删除成功记录数
     */
    int deleteById(Serializable id);

    /**
     * 3、根据实体(ID)删除
     *
     * @param entity 实体对象
     * @return 删除成功记录数
     */
    int deleteById(T entity);

    /**
     * 4、根据 columnMap 条件，删除记录
     * @param columnMap 表字段 map 对象
     * @return 删除成功记录数
     */
    int deleteByMap(Map<String, Object> columnMap);

    /**
     * 5、根据 entity 条件，删除记录
     * @param queryWrapper 实体对象封装操作类（可以为 null,里面的 entity 用于生成 where 语句）
     * @return 删除成功记录数
     */
    int delete( Wrapper<T> queryWrapper);

    /**
     * 6、删除（根据ID或实体 批量删除）
     * @param idList 主键ID列表或实体列表(不能为 null 以及 empty)
     * @return 删除成功记录数
     */
    int deleteBatchIds(Collection<?> idList);

    /**
     * 7、根据 ID 修改
     * @param entity 实体对象
     * @return 修改成功记录数
     */
    int updateById(T entity);

    /**
     * 8、根据 whereEntity 条件，更新记录
     * @param entity        实体对象 (set 条件值,可以为 null)
     * @param updateWrapper 实体对象封装操作类（可以为 null,里面的 entity 用于生成 where 语句）
     * @return 修改成功记录数
     */
    int update(T entity,Wrapper<T> updateWrapper);

    /**
     * 9、根据 ID 查询
     * @param id 主键ID
     * @return 查找到到实体
     */
    T findById(Serializable id);

    /**
     * 10、查询（根据ID 批量查询）
     * @param idList 主键ID列表(不能为 null 以及 empty)
     * @return 查找到到实体list
     */
    List<T> selectBatchIds(Collection<? extends Serializable> idList);

    /**
     * 11、查询（根据 columnMap 条件）
     * @param columnMap 表字段 map 对象
     * @return 查找到到实体list
     */
    List<T> selectByMap(Map<String, Object> columnMap);

    /**
     * 12、根据 entity 条件，查询一条记录
     * <p>查询一条记录，例如 qw.last("limit 1") 限制取一条记录, 注意：多条数据会报异常</p>
     * @param queryWrapper 实体对象封装操作类（可以为 null）
     * @return 查找到到实体
     */
    default T selectOne(Wrapper<T> queryWrapper) {
        List<T> ts = this.selectList(queryWrapper);
        if (!CollectionUtils.isEmpty(ts)) {
            if (ts.size() != 1) {
                throw new BaseSqlException("One record is expected, but the query result is multiple records");
            }
            return ts.get(0);
        }
        return null;
    }

    /**
     * 13、根据 Wrapper 条件，判断是否存在记录
     * @param queryWrapper 实体对象封装操作类
     * @return boolean
     */
    default boolean exists(Wrapper<T> queryWrapper) {
        Long count = this.selectCount(queryWrapper);
        return null != count && count > 0;
    }

    /**
     * 14、根据 Wrapper 条件，查询总记录数
     * @param queryWrapper 实体对象封装操作类（可以为 null）
     * @return 返回记录数
     */
    Long selectCount(Wrapper<T> queryWrapper);

    /**
     * 15、根据 entity 条件，查询全部记录
     * @param queryWrapper 实体对象封装操作类（可以为 null）
     * @return 返回列表
     */
    List<T> selectList(Wrapper<T> queryWrapper);

    /**
     * 16、查询全部记录
     * @return 返回列表 List<T>
     */
    List<T> findAll();

    /**
     * 17、根据 Wrapper 条件，查询全部记录，返回多个字段值列表
     * @param queryWrapper 实体对象封装操作类（可以为 null）
     * @return List<Map<String, Object>>
     */
    List<Map<String, Object>> selectMaps(Wrapper<T> queryWrapper);

    /**
     * 18、根据 Wrapper 条件，查询某个字段值列表
     * <p>18、注意： 只返回第一个字段的值</p>
     * @param queryWrapper 实体对象封装操作类（可以为 null）
     * @return List<Object>
     */
    List<T> selectOneColumnList(Wrapper<T> queryWrapper);



    /**
     * 根据 entity 对应数据库字段 条件，查询全部记录（分页）
     * @param page  分页查询条件（可以为 RowBounds.DEFAULT）
     * @param queryWrapper   实体对象封装操作类（可以为 null）
     * @param <P>
     * @return
     */
    <P extends IPage<T>> P selectPage(P page, Wrapper<T> queryWrapper);


    /**
     * 根据 Wrapper 条件，查询全部记录（并翻页）
     * @param page 分页查询条件
     * @param queryWrapper 实体对象封装操作类
     * @param <P>
     * @return
     */
    <P extends IPage<Map<String, Object>>> P selectMapsPage(P page,Wrapper<T> queryWrapper);

    /**
     * 批量插入
     * @param list
     * @return
     */
    int[] batchSave(List<T> list);

    /**
     * 保存或者更新，如果bean id为为空 更新
     * @param entity
     * @return
     */
    int saveOrUpdate(T entity);
}
